use derive_builder::Builder;
use serde::{Deserialize, Serialize};

use super::{
    ClassAttribute, ClassAttributeBuilder, ClassGetter, ClassRelation, ClassRelationBuilder,
    Domain, RelationRelatedType,
};
use crate::error::Error;
use crate::mapper::ValueMapper;
use crate::modeling::{
    ClassAttributePersistence, ClassPersistence, ClassPersistenceBuilder, ClassPersistenceGetter,
    ClassRelationGetter, Value, ValueType,
};

pub const CLASS_CLASS_IDENTIFIER: &'static str = "g01_class";

pub const CLASS_CLASS_NAME: &'static str = "class";

pub const CLASS_TABLE_NAME: &'static str = "_g01_meta_classes";

#[derive(Debug, Serialize, Deserialize, Default, Clone, Builder, PartialEq)]
#[builder(name = "ClassBuilder")]
#[builder(pattern = "mutable")]
#[builder(setter(into, strip_option), default)]
#[builder(derive(Debug))]
#[builder(build_fn(error = "Error"))]
pub struct Class {
    /// id
    pub id: i64,
    /// domain identifier
    pub domain_identifier: String,
    /// identifier
    pub identifier: String,
    /// 名称
    pub name: String,
    /// 名称
    pub title: String,
    /// 图标
    pub icon: Option<String>,
    /// 数据是否是类型
    pub data_is_type: bool,
    /// 是否持久化
    pub is_persistent: bool,
    /// 持久化
    pub persistence: Option<String>,
    /// 逻辑主键
    pub primary_key: String,
    /// 选项
    pub options: Option<String>,
    /// 备注
    pub description: Option<String>,
    // 创建时间
    pub created_at: i64,
    // 更新时间
    pub updated_at: i64,
    // 属性
    pub attributes: Option<Vec<ClassAttribute>>,
}

impl ValueMapper for Class {}

//
crate::impl_from_value!(Class);
crate::impl_class_persistence_getter!(Class, CLASS_TABLE_NAME);

impl ClassGetter for Class {
    fn get_name() -> anyhow::Result<String> {
        Ok(String::from(CLASS_CLASS_NAME))
    }
    fn get_identifier() -> anyhow::Result<String> {
        Ok(String::from(CLASS_CLASS_IDENTIFIER))
    }
    fn get_class() -> anyhow::Result<Class> {
        let mut attribute_builder = ClassAttributeBuilder::default();
        attribute_builder.class_identifier(CLASS_CLASS_IDENTIFIER);

        let mut commons = super::common_attributes_with_builder(&attribute_builder)?;
        let mut append = vec![
            attribute_builder
                .clone()
                .name("domain_identifier")
                .title("领域")
                .position(11)
                .data_type(ValueType::String)
                .build()?,
            attribute_builder
                .clone()
                .name("data_is_type")
                .title("数据是否是类型")
                .position(12)
                .data_type(ValueType::Boolean)
                .build()?,
            attribute_builder
                .clone()
                .name("is_persistent")
                .title("持久化")
                .position(13)
                .data_type(ValueType::Boolean)
                .build()?,
            attribute_builder
                .clone()
                .name("persistence")
                .title("持久化信息")
                .position(13)
                .data_type(ValueType::String)
                .build()?,
            attribute_builder
                .clone()
                .name("primary_key")
                .title("主键")
                .position(14)
                .data_type(ValueType::String)
                .build()?,
        ];
        append.append(&mut commons);
        append.sort_by(|a, b| a.position.cmp(&b.position));

        let clazz = ClassBuilder::default()
            .identifier(String::from(CLASS_CLASS_IDENTIFIER))
            .name(CLASS_CLASS_NAME)
            .data_is_type(true)
            .is_persistent(true)
            .primary_key(String::from("identifier"))
            .attributes(append)
            .build()?;
        Ok(clazz)
    }
}

impl Class {
    ///获取属性的数据类型
    pub fn attribute(&self, attribute_name: &String) -> anyhow::Result<ClassAttribute> {
        //
        if let Some(attributes) = &self.attributes {
            for attribute in attributes {
                if &attribute.name == attribute_name {
                    //
                    return Ok(attribute.clone());
                }
            }
            Err(anyhow::anyhow!(
                "class[{}]属性[{}]没有找到!",
                Self::get_identifier()?,
                attribute_name
            ))
        } else {
            Err(anyhow::anyhow!(
                "class[{}]的数据中没有设置attributes!",
                Self::get_identifier()?
            ))
        }
    }
}

crate::impl_class_relations_getter!(
    Class,
    vec![ClassRelationBuilder::default()
        .src_identifier(Domain::get_identifier()?)
        .target_identifier(Self::get_identifier()?)
        .related_type(RelationRelatedType::Keys)
        .related_at("domain_identifier")
        .build()?]
);
